package com.jxmcloud.business.cut.service.impl.user;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.jxmcloud.business.cut.constants.CutErrorMsg;
import com.jxmcloud.business.cut.constants.CutRedisConstant;
import com.jxmcloud.business.cut.dto.admin.AdminUserMergerDto;
import com.jxmcloud.business.cut.dto.client.LoginNameDto;
import com.jxmcloud.business.cut.enums.UserStatus;
import com.jxmcloud.business.cut.mapper.database.IInviteSuccessDBMapper;
import com.jxmcloud.business.cut.model.database.DBUserFlowInfo;
import com.jxmcloud.business.cut.model.database.DBUserLoginInfo;
import com.jxmcloud.business.cut.service.database.IUserActivityInfoDBService;
import com.jxmcloud.business.cut.service.database.IUserBagDBService;
import com.jxmcloud.business.cut.service.database.IUserFlowDBService;
import com.jxmcloud.business.cut.service.database.IUserLoginInfoDBService;
import com.jxmcloud.business.cut.service.user.*;
import com.jxmcloud.business.cut.util.MyTool;
import com.jxmcloud.business.cut.util.VipRpcUtil;
import com.jxmcloud.business.cut.util.XuanleRpcUtil;
import com.jxmcloud.business.cut.vo.toDb.ToDbUserBase;
import com.jxmcloud.business.cut.vo.user.MasterVo;
import com.jxmcloud.business.cut.vo.user.PlayerInfoVo;
import com.jxmcloud.business.cut.vo.user.UserFlowVo;
import com.xlcloud.platform.api.exception.BusinessException;
import com.xlcloud.platform.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.util.function.Tuple2;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 基础类数据接口
 */
@Service
@Slf4j
public class UserManagerServiceImpl implements IUserManagerService {
    public static final int LOCK_TIME = 3;
    //
    private static final ConcurrentHashMap<Integer, Integer> actionLock = new ConcurrentHashMap<>();
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private IInviteSuccessDBMapper inviteSuccessMapper;
    @Resource
    private IUserFlowDBService flowInfoDBService;
    @Resource
    private VipRpcUtil vipRpcUtil;
    @Resource
    private IUserBaseService userBaseService;
    @Resource
    private IUserBagService userBagService;
    @Resource
    private IUserActivityService userActivityService;
    @Resource
    private IUserActivityInfoDBService userActivityInfoDBService;
    @Resource
    @Lazy  // 添加延迟加载注解
    private IUserOrderService userOrderService;
    @Resource
    private IUserCashDetailListService userCashDetailListService;
    @Resource
    private IUserFlowService userFlowService;
    @Resource
    private IUserDrawTurnService userDrawTurnService;
    @Resource
    private IUserBagDBService userBagDBService;
    @Autowired
    private IUserLoginInfoDBService userLoginInfoDBService;
    @Autowired
    private XuanleRpcUtil xuanleRpcUtil;

    /**
     * 创建新角色
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PlayerInfoVo makeNewPlayer(String account) {
        PlayerInfoVo newPlayer = new PlayerInfoVo();
        boolean flag = userBaseService.createByAccount(newPlayer, account);
        if (!flag) {
            log.error("用户数据创建失败: userBaseService");
            return null;
        }
        Integer uid = newPlayer.getBase().getUid();
        flag = userActivityService.register(newPlayer, uid);
        if (!flag) {
            log.error("用户数据创建失败: userActivityService");
        }
        flag = userBagService.register(newPlayer, uid);
        if (!flag) {
            log.error("用户数据创建失败: userBagService");
        }
        flag = userCashDetailListService.register(newPlayer, uid);
        if (!flag) {
            log.error("用户数据创建失败: userCashDetailListService");
        }
        flag = userFlowService.register(newPlayer, uid);
        if (!flag) {
            log.error("用户数据创建失败: userFlowService");
        }
        flag = userDrawTurnService.register(newPlayer, uid);
        if (!flag) {
            log.error("用户数据创建失败: userDrawTurnService");
        }

        return newPlayer;
    }

    @Override
    public PlayerInfoVo loadPlayerFromDb(Integer uid) {
        PlayerInfoVo newPlayer = new PlayerInfoVo();
        // 获取所有模块
        boolean flag = userBaseService.loadFromDb(newPlayer, uid);
        if (!flag) {
            log.error("用户数据加载失败: userBaseService");
        }
        flag = userActivityService.loadFromDb(newPlayer, uid);
        if (!flag) {
            log.error("用户数据加载失败: userActivityService");
        }
        flag = userBagService.loadFromDb(newPlayer, uid);
        if (!flag) {
            log.error("用户数据加载失败: userBagService");
        }
        flag = userCashDetailListService.loadFromDb(newPlayer, uid);
        if (!flag) {
            log.error("用户数据加载失败: userCashDetailListService");
        }
        flag = userFlowService.loadFromDb(newPlayer, uid);
        if (!flag) {
            log.error("用户数据加载失败: userFlowService");
        }
        flag = userDrawTurnService.loadFromDb(newPlayer, uid);
        if (!flag) {
            log.error("用户数据加载失败: userDrawTurnService");
        }
        return newPlayer;
    }

    @Override
    public Integer getUidByAccount(String account) {
        DBUserLoginInfo dbUserLoginInfo = userLoginInfoDBService.selectByAccount(account);
        if (ObjectUtil.isNotNull(dbUserLoginInfo)) {
            return dbUserLoginInfo.getUid();
        }
        return 0;
    }

    @Override
    public void refreshPlayerCache(PlayerInfoVo player) {
        // refreshRedis
        RBucket<PlayerInfoVo> bucket = redissonClient.getBucket(CutRedisConstant.getUserInfoKey(player.getBase().getUid().toString()), JsonJacksonCodec.INSTANCE);
        bucket.set(player);
        bucket.expire(Duration.ofSeconds(CutRedisConstant.EXPIRED_TIME));

        // refreshDb
        MasterVo master = player.getMaster();
        Set<String> saveList = master.getSaveList();
        saveList.forEach(key -> {
            userBaseService.saveToDb(player, key);
            userBagService.saveToDb(player, key);
            userActivityService.saveToDb(player, key);
            userOrderService.saveToDb(player, key);
            userCashDetailListService.saveToDb(player, key);
            userFlowService.saveToDb(player, key);
            userDrawTurnService.saveToDb(player, key);
        });
        saveList.clear();
    }

    @Override
    public PlayerInfoVo getUserInfoByUid(Integer uid) {
        DBUserLoginInfo dbUser = userLoginInfoDBService.selectOne(uid);
        if (ObjectUtil.isNull(dbUser)) {
            log.info("未找到用户: " + uid);
            return null;
        }
        String session = dbUser.getSessionKey();
        if (!MyTool.isTure(session)) {
            log.error("获取的用户session为空: {}", uid);
            return null;
        }
        return this.getUserInfo(session);
    }

    @Override
    public PlayerInfoVo getUserInfo(String session) {
        // 进行加密UID
        String uid = MyTool.getUidBySessionKey(session);
        if (ObjectUtil.isNull(uid)) {
            log.error("用户UID为空: " + session);
            return null;
        }

        RBucket<PlayerInfoVo> bucket = redissonClient.getBucket(CutRedisConstant.getUserInfoKey(uid), JsonJacksonCodec.INSTANCE);
        PlayerInfoVo userInfo = bucket.get();
        if (userInfo != null) {
            // 验证Session是否有效
            if (!userInfo.getBase().getSession().equals(session)) {
                log.error("{} 用户session无效,请重新登录 ", uid);
                return null;
            }
            // 状态
            boolean isNormal = this.isUserStatusNormal(userInfo);
            if (!isNormal) {
                log.info("{} 用户状态异常", uid);
                return null;
            }
            return userInfo;
        }
        return null;
    }

    private void setPlayerLock(Integer uid) {
        int nowTime = (int) (System.currentTimeMillis() / 1000);
        Integer lockTime = nowTime + LOCK_TIME;
        this.actionLock.put(uid, lockTime);
    }

    public boolean checkPlayerLock(Integer uid) {
        return false;
//        Integer lockTime = this.actionLock.get(uid);
//        if (ObjectUtil.isNull(lockTime)) {
//            this.setPlayerLock(uid);
//            return false;
//        }
//        Integer nowTime = MyTool.getCurrentTimeSecond(null);
//        if (nowTime > lockTime) {
//            this.setPlayerLock(uid);
//            return false;
//        }
//        return true;
    }

    public void removePlayerLock(Integer uid) {
        this.actionLock.remove(uid);
    }

    private UserFlowVo getUserActivityFlowInfo(String uid, Integer activityId) {
        DBUserFlowInfo dbUserFlowInfo = flowInfoDBService.lambdaQuery().eq(DBUserFlowInfo::getUid, uid).eq(DBUserFlowInfo::getActivityId, activityId).one();
        if (Objects.isNull(dbUserFlowInfo)) {
            return new UserFlowVo();
        }
        return BeanUtil.copyProperties(dbUserFlowInfo, UserFlowVo.class);
    }

    @Override
    public LoginNameDto checkByAccount(String account) {
        String error = CutErrorMsg.ERROR_TRUE;
        int code = CutErrorMsg.ERROR_CODE_FAIL;
        LoginNameDto loginNameDto = null;
        do {
            //预留检测玄乐平台账号是否异常
            loginNameDto = xuanleRpcUtil.getUserInfoByLoginName(account);
            if (ObjectUtil.isNull(loginNameDto)) {
                error = CutErrorMsg.ERROR_RELOGIN;
                break;
            }
            if(ObjectUtil.isEmpty(loginNameDto.getMobile())) {
                error = CutErrorMsg.ERROR_NO_PHONE;
                code = CutErrorMsg.ERROR_CODE_LACK_PHONE;
                break;
            }
            //查询账号信息
            DBUserLoginInfo dbUserLoginInfo = userLoginInfoDBService.selectByAccount(account);
            //是老账号 ，状态异常
            if (ObjectUtil.isNotEmpty(dbUserLoginInfo) && UserStatus.BANNED.getValue().equals(dbUserLoginInfo.getStatus())) {
                //封禁时间为空，永久封禁
                if (ObjectUtil.isEmpty(dbUserLoginInfo.getBannedTime())) {
                    error = CutErrorMsg.ERROR_NO_ACCOUNT;
                    break;
                }
                //封禁时间为空，截止时间封禁
                if (ObjectUtil.isNotEmpty(dbUserLoginInfo)) {
                    error = String.format(CutErrorMsg.ERROR_NO_ACCOUNT_TIME, DateUtil.dateToTime(dbUserLoginInfo.getBannedTime()));
                    break;
                }
            }
            loginNameDto.setUid(Optional.ofNullable(dbUserLoginInfo).map(d->d.getUid()).orElse(0));
        } while (false);
        if (!error.equals(CutErrorMsg.ERROR_TRUE)) {
            // 抛出异常
            throw new BusinessException(code, error);
        }
        return loginNameDto;
    }

    @Override
    public PlayerInfoVo getUserInfoByAccount(String account) {
        DBUserLoginInfo dbUser = userLoginInfoDBService.selectByAccount(account);
        if (ObjectUtil.isNull(dbUser)) {
            log.error("未找到用户: " + account);
            return null;
        }
        String session = dbUser.getSessionKey();
        if (session.isEmpty()) {
            log.error("用户session为空: " + account);
            return null;
        }
        return this.getUserInfo(session);
    }

    /**
     * 用户状态是否正常
     * @param player
     * @return
     */
    @Override
    public boolean isUserStatusNormal(PlayerInfoVo player) {
        Integer status = player.getBase().getStatus();
        if (ObjectUtil.isNull(status)) {
            return true;
        }
        if (status.equals(UserStatus.NORMAL.getValue())) {
            return true;
        }
        return false;
    }

    @Override
    public void updateUserStatus(AdminUserMergerDto dto) {
        PlayerInfoVo player = this.getUserInfoByAccount(dto.getAccount());
        //没有登录,直接修改库
        if (ObjectUtil.isEmpty(player)) {
            userLoginInfoDBService.updateUserStatusInfo(ToDbUserBase.pageData(dto));
        } else {
            //登录了
            userBaseService.checkParam(dto.getBannedTime());
            userBaseService.updateUserStatusData(player, dto);
            this.refreshPlayerCache(player);
        }
    }

}
